const CronJob = require('cron').CronJob;
const es = require('../elasticsearch');
const robot = require('../dingtalk');
const debug = require('debug');
const log = debug('viewdata:cron:dingding');

// 安全域名 / IP
const moonIds = {
  // 洪宁
  uhbw5w5bw: { name: 'H5', member: '17682308560', limit: 50 },
  // 明坡
  w6med1ddc: { name: '营销H5', member: '17638277550', limit: 10 },
  // 吕焕
  z4vqsqclx: { name: '小程序', member: '18457029994', limit: 10 },
  // 姚远
  ijmtxxg4t: { name: 'ios客户端', member: '15658858626', limit: 10 },
  // 姚远
  pn8njdku4: { name: 'android客户端', member: '15658858626', limit: 10 },
  // 方宝
  jw0pzj9nh: { name: 'crm管理后台', member: '17601055033', limit: 10 },
  // 方宝
  d3wjwmqep: { name: '供应商管理后台', member: '17601055033', limit: 10 },
  // 方宝
  wmeie5fga: { name: '小店管理后台', member: '17601055033', limit: 10 },
  // 韩美兰
  anywd3b1d: { name: '喜团生鲜小程序', member: '18234099705', limit: 10 },
  // 方宝
  tf5av6mgf: { name: 'wms管理后台', member: '17601055033', limit: 10 },
  // 明坡
  ybweh0pvp: { name: '喜团生鲜H5', member: '17638277550', limit: 10 },
  // 姚远
  '2tp4ijfgw': { name: '供应商H5', member: '15658858626', limit: 10 },
};

function zeroFill(num) {
  return num > 9 ? num : '0' + num;
}

function dateFormat(timestamp) {
  const date = new Date(timestamp);
  date.setHours(date.getHours() - 8);
  return (
    date.getFullYear() +
    '-' +
    zeroFill(date.getMonth() + 1) +
    '-' +
    zeroFill(date.getDate()) +
    'T' +
    zeroFill(date.getHours()) +
    ':' +
    zeroFill(date.getMinutes()) +
    ':' +
    zeroFill(date.getSeconds()) +
    '.' +
    date.getMilliseconds() +
    'Z'
  );
}

const matchPhrase = function (key, value) {
  return {
    match_phrase: { message: `"${key}":"${value}"` },
  };
};

const range = function (start, end) {
  return {
    range: {
      '@timestamp': {
        gte: start ? dateFormat(start) : '',
        lte: end ? dateFormat(end) : '',
        format: 'strict_date_optional_time',
      },
    },
  };
};

// 获取es数据
function getEsData(start, end, limit) {
  return new Promise(function (resolve, reject) {
    es(
      [range(start, end)],
      function (error, res) {
        let list = [];
        try {
          list = JSON.parse(res.body).hits.hits.map((v) => {
            const [, time, message] = v._source.message.match(/^(\d+-\d+-\d+\s\d+:\d+:\d+\.\d+\s)(.+)/);
            return {
              ...JSON.parse(message),
              es_at: new Date(time).getTime(),
            };
          });
        } catch (e) {
          console.log(e);
        }
        return resolve(list);
      },
      { size: limit },
    );
  });
}

// 合并数据
function combine(list) {
  const result = {};
  // 获取数组的key
  function getKey(item) {
    const keyMap = {
      logdebug_op: (v) => ({
        t: v.t,
        moonid: v.moonid,
        url: v.url,
        code: v.code,
      }),
      logdebug_js: (v) => ({
        t: v.t,
        moonid: v.moonid,
        name: v.name,
        message: v.message,
      }),
    };
    const key = keyMap[item.t] ? keyMap[item.t](item) : '';
    return key ? JSON.stringify(key) : '';
  }

  for (const item of list) {
    let key = getKey(item);
    if (key) {
      result[key] ? result[key].push(item) : (result[key] = [item]);
    }
  }
  return result;
}

// 生成钉钉消息
function getDingNotices(data, count, time) {
  const result = [];
  // 生成单条钉钉消息
  function getDingNotice(item, len, time, errorData) {
    const formatTime = dateFormat(time + 8 * 60 * 60 * 1000);
    const moon = moonIds[item.moonid] || {};
    const notiveMap = {
      logdebug_op: (v) => ({
        at: len > moon.limit,
        member: moon.member,
        text:
          `MoonId: ${moon.name || v.moonid}\n\n` +
          `时间: ${formatTime}\n\n` +
          `次数: 5分钟${len}次\n\n` +
          `类型: 接口异常\n\n` +
          `异常接口: ${v.url}\n\n` +
          `code: ${v.code}\n\n` +
          `res: ${JSON.stringify(errorData.res || '').slice(0, 500)}\n\n` +
          `访问以下地址可查看更多错误信息: [http://192.168.20.34:88/admin/viewsearchdata](http://192.168.20.34:88/admin/viewsearchdata) \n\n`,
      }),
      logdebug_js: (v) => ({
        at: len > moon.limit,
        member: moon.member,
        text:
          `MoonId: ${moon.name || v.moonid}\n\n` +
          `时间: ${formatTime}\n\n` +
          `次数: 5分钟${len}次\n\n` +
          `类型: 脚本错误\n\n` +
          `错误样例: [${v.name}] ${v.message}\n\n` +
          `stack: ${errorData.stack.slice(0, 500)}\n\n` +
          `访问以下地址可查看更多错误信息: [http://192.168.20.34:88/admin/viewsearchdata](http://192.168.20.34:88/admin/viewsearchdata) \n\n`,
      }),
    };
    // b端特殊处理，过滤正常数据请求 '00000'
    if (moon.member === '17601055033' && errorData.res && errorData.res.code === '00000') {
      return
    }
    return notiveMap[item.t] && notiveMap[item.t](item);
  }
  for (const key in data) {
    if (data[key].length > count) {
      const notice = getDingNotice(JSON.parse(key), data[key].length, time, data[key][0]);
      notice && result.push(notice);
    }
  }
  return result;
}

// 发送钉钉消息
async function dingdingSend() {
  log('dingdingSend');

  // es 单页获取数据的数量
  const limit = 500;
  // 单位时间内报错超过多少次, 生成钉钉消息
  const errorLimit = 20;

  // 结束时间
  const end = Date.now();
  // 开始时间
  const start = end - 5 * 60 * 1000;

  // 获取 从开始时间 到 结束时间 内的500条数据
  const esData = await getEsData(start, end, limit);
  log('dingdingSend', 'esData length', esData.length);

  // 对es数据进行合并
  const combineEsData = combine(esData);

  // 针对单位时间内报错超过 20 次的问题
  // 生成钉钉消息
  const notices = getDingNotices(combineEsData, errorLimit, end);
  log('dingdingSend', 'notices length', notices.length);

  // 循环发送消息
  notices.forEach((notice) => {
    // 如果需要@人
    if (notice.at) {
      return robot.at(notice.member).markdown('线上异常通知', notice.text + `@${notice.member}`)
    }
    robot.markdown('线上异常通知', notice.text);
  });
}

new CronJob('0 */5 * * * *', dingdingSend, null, true);
